package net.bat.rest;

import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import net.bat.dao.QueryResult;
import net.bat.dao.UserDAO;
import net.bat.dto.ResultDTO;
import net.bat.entity.IdEntity;
import net.bat.filter.ExtJSFilter;
import net.bat.filter.ExtJSSort;
import net.bat.filter.ExtReq;
import net.bat.filter.HibernateUtil;
import net.bat.filter.JPAReq;

import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

@Service
public class RestService {
	@Autowired
	private UserDAO dao;

	@Autowired
	private HibernateUtil hibernateUtil;

	private ExtReq parser = new ExtReq();

	public <T extends IdEntity> ResultDTO<?> getEntities(int page, int start, int limit, String filter, String sort,
			String entity_name) throws Exception {
		ResultDTO<T> dto = new ResultDTO<T>();
		Class<T> cls = UserDAO.classForName(entity_name);
		JPAReq req = parser.parse(filter, sort, cls);

		QueryResult<T> result = dao.getScrollData(cls, start, limit, req.getWhereql(), req.getQueryParams(),
				req.getOrderby());
		dto.data = result.getResultlist();
		dto.total = result.getTotalrecord();
		return dto;
	}

	public <T extends IdEntity> T updateEntity(String entity_name, Object id, Map<String, Object> rmap)
			throws Exception {
		dao.update(entity_name, id, rmap);
		return null;
	}

	public <T extends IdEntity> T addEntity(String entity_name, Map<String, Object> rmap) throws Exception {
		dao.add(entity_name, null, rmap);
		return null;
	}

	public <T extends IdEntity> T removeEntitys(String entity_name, Object[] ids) throws Exception {
		dao.remove(entity_name, ids);
		return null;
	}

	/**
	 * @param filter
	 * @param entity
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> List<Criterion> getHibernateFilters(String filter, Class<T> entity) {
		List<Criterion> criterias = null;
		if ((filter != null) && !"".equals(filter)) {
			ObjectMapper objectMapper = new ObjectMapper();
			JavaType type = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, ExtJSFilter.class);
			List<ExtJSFilter> filters;
			try {
				filters = (List<ExtJSFilter>) objectMapper.readValue(filter, type);
				criterias = getCriteriaList(filters, entity);
			} catch (JsonParseException e) {
				e.printStackTrace();
			} catch (JsonMappingException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (ParseException e) {
				e.printStackTrace();
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			}
		}
		return criterias;
	}

	/**
	 * @param filters
	 * @param entity
	 * @return
	 * @throws SecurityException
	 * @throws ParseException
	 * @throws NoSuchFieldException
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws IOException
	 */
	private <T> List<Criterion> getCriteriaList(List<ExtJSFilter> filters, Class<T> entity) throws SecurityException,
			ParseException, NoSuchFieldException, JsonParseException, JsonMappingException, IOException {
		List<Criterion> criterias = new ArrayList<Criterion>();
		if (filters != null) {
			criterias = hibernateUtil.getRestrictions(filters, entity);
		}
		return criterias;
	}

	/**
	 * @param sort
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Order> getHibernateOrders(String sort) {
		List<Order> orders = null;
		if ((sort != null) && !"".equals(sort)) {
			ObjectMapper objectMapper = new ObjectMapper();
			JavaType type = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, ExtJSSort.class);
			List<ExtJSSort> sorts;
			try {
				sorts = (List<ExtJSSort>) objectMapper.readValue(sort, type);
				orders = getOrderList(sorts);
			} catch (JsonParseException e) {
				e.printStackTrace();
			} catch (JsonMappingException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			}
		}
		return orders;
	}

	/**
	 * @param sorts
	 * @return
	 */
	private List<Order> getOrderList(List<ExtJSSort> sorts) {
		List<Order> orders = new ArrayList<Order>();
		if (sorts != null) {
			orders = hibernateUtil.getOrders(sorts);
		}
		return orders;
	}

}
